Feat(wallet): build TransactionSignerPanel component (#222) - #301
Merged
godamongstmen897 merged 201 commits intoAug 31, 2026
Merged
Conversation
- Add DEFAULT_SIGNING_TIMEOUT_MS = 60_000 configurable constant - Add TxSignRequest interface, TxSignatureTimeoutError class, clearTxSensitiveMemory helper, and signTxWithTimeout function to app/lib/transactions.ts, matching the setTimeout + Promise.race pattern used by all other connector helpers in the codebase - Wire signTxWithTimeout into submitContractTransaction via optional signingTimeoutMs param (defaults to the constant); on timeout the operation is aborted and any sensitive payload memory is zeroed - Add __tests__/transactions_timeout.test.ts with 21 test cases covering: timeout fires, memory cleared, successful signing flow, pre-deadline no-early-fire, timer cleanup, error propagation, default constant, TxSignatureTimeoutError class, and clearTxSensitiveMemory helper
Adds app/components/TransactionSignerPanel.tsx — a wallet-agnostic sign-transaction interface that unblocks issue Goldii-locks#222 (RTL tests). - Parses supplied XDR on mount via useWalletMultiSigAssembly.parseStructure and displays a structure preview (source account, fee, operation count, existing signatures) - States: idle -> signing -> success | error | parse-error - Sign button delegates to hook.signTransaction(xdr, signTransaction) — no new XDR parsing or signing logic introduced - Retry button returns to idle on signing failure - Cancel/Dismiss calls onRejected() and resets state - onSigned, onRejected, onError callbacks for parent integration - Works for all four supported wallets (freighter, albedo, xbull, hana) through the unified useWalletMultiSigAssembly hook
- Replace hardcoded empty message with EmptyStateCard component - Display briefcase icon for job-related context - Show descriptive title and explanation text - Include role badges (Client, Freelancer, Arbiter) showing available participation options - Add comprehensive test coverage with 16 test cases - Ensure proper accessibility with region landmarks and aria-labels - Validates placeholder display under empty data states
…, desktop - Add responsive padding and spacing (px-3 sm:px-6) for mobile-first approach - Implement responsive typography scaling (text-xl sm:text-2xl md:text-3xl) - Stack layout vertically on mobile, horizontal on tablet/desktop - Apply responsive grid layouts (grid-cols-1 sm:grid-cols-2 lg:grid-cols-3) - Make search form full-width on mobile, inline on tablet+ - Add responsive gaps and margins throughout - Implement horizontal overflow handling for pagination on mobile - Reduce button padding and font sizes on mobile viewports - Add comprehensive responsive design test suite with 20 test cases - Validate layout at mobile (< 640px), tablet (640-1024px), desktop (> 1024px)
…yling - Add focus-visible ring-2 styling on all interactive elements (indigo-500) - Implement hover state transitions with smooth animations (transition-all duration-200) - Add active state styling for button press feedback - Style disabled buttons with opacity-50 and cursor-not-allowed - Prevent hover effects on disabled buttons (disabled:hover:bg-gray-900) - Apply ring-offset for focus states on dark background (ring-offset-gray-950) - Use inset focus ring on job expand buttons for better UX - Add focus-visible:outline-none to remove browser defaults - Implement smooth transitions on all state changes - Add comprehensive test suite with 25 test cases validating: - Search input focus and hover states - Search button focus, hover, and active states - Role filter button states and transitions - Job expand button interactive states - Pagination button states and disabled styling - Accessibility compliance and transitions
…vigation, semantic HTML)
…onSignerPanel - Move state declarations before closeModal callback (WalletSelectorModal) - Remove eslint-disable and add missing hook dependency (TransactionSignerPanel)
|
@MAN7A-afk Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
Implements the app dark/light theme toggle as a keyboard-operable, ARIA-compliant switch (role=switch, aria-checked, aria-label) that persists the chosen theme to localStorage and applies it to the document root. Adds React Testing Library tests verifying node rendering, accessible state, theme application, keyboard operation and persistence. Closes Goldii-locks#319
Implements the navbar alert bell badge as a keyboard-operable (role=button) disclosure with ARIA compliance (Goldii-locks#320): accessible name, aria-haspopup/aria-expanded/aria-controls, aria-live announcement regions, aria-hidden on decorative glyphs, focus-visible rings and design-token contrast. Adds field error indicators and alerts (Goldii-locks#324): validation field configs render role=alert error text that toggles as validation triggers, wired via aria-describedby and counted toward the unread badge. Adds React Testing Library tests covering both requirements. Closes Goldii-locks#320 Closes Goldii-locks#324
Stack the stat grid and content rows to a single column on mobile, two on tablet, three on desktop, and use responsive padding/spacing so LoadingSkeleton scales cleanly at every breakpoint. Closes Goldii-locks#275
Fade the skeleton in on mount (animate-fade-in) instead of popping in abruptly, and stagger each placeholder bar's pulse animation-delay so the loading state reads as a smooth wave rather than a flat blink. Closes Goldii-locks#278
Replace the bare "No jobs found" line with a reusable EmptyState component (icon, heading, supporting copy) shown once loading finishes with zero jobs for the connected wallet. Closes Goldii-locks#276
…k-switcher-responsive fix(Goldii-locks#312): Add responsive sizing layouts on dark_mode_switcher
…ing-skeleton-stories feat: add Storybook stories for LoadingSkeleton (closes Goldii-locks#281)
…e_raise_modal Implement overlay wrappers on dispute_raise_modal to fit constraints on mobile device screen heights. Changes: - Added overlayWrapper class with flex layout and max-h-[92vh] for mobile height constraints - Added scrollableContent class to allow middle content to scroll independently - Updated panel structure to use overlay wrapper with header, scrollable content, and actions - Added flex-shrink-0 to header and actions to prevent shrinking - Added comprehensive test cases for mobile viewport validation
No textual conflict against current main -- GitHub's cached mergeability had gone stale (it reported DIRTY where a local three-way merge is clean), the same as on Goldii-locks#366. Merging main in here refreshes the head so CI runs against it. lint 0 errors / tsc 0 errors / 2035 tests passing / build OK
…e-modal-stories Feat: Implemented Storybook Interface for Dispute Raise ModaL
…he shared badge This branch predates the LoadingSkeleton rewrite (Goldii-locks#349/Goldii-locks#351/Goldii-locks#352/Goldii-locks#354) and the WalletBadge consolidation, and git merged it without conflicts into something that does not parse -- the classic silent damage: - LoadingSkeleton.tsx ended up as this branch's pre-token markup concatenated with main's current component, leaving an unterminated JSX block followed by `interface LoadingSkeletonProps`. - WalletBadge.tsx ended up with two complete implementations: two `formatAddress` declarations and two `export default`s. - Navbar.tsx and wallet_badge.test.tsx each got duplicate import lines. LoadingSkeleton and SignatureTimeoutAlert are incidental to this PR -- its subject is the wallet badge -- and the branch's own copies were already broken before the merge (its SignatureTimeoutAlert interleaves a useEffect into the existing useMemo, leaving two catch blocks and an undefined setParseMessage). Both were taken from main. The badge work itself is real and entirely additive: 16 of its 33 cases already passed against main's component, and the other 17 cover features main did not have. Those were added to main's derived-status rendering rather than replacing it: isValidStellarAddress exported; G + 55 base32 chars, format only error / fieldError wallet-field-error + wallet-error-text, aria-invalid, red status dot validateAddress flags a malformed address the same way alert wallet-alert-badge, amber dot; error wins empty placeholders wallet-badge-placeholder, -custom and wallet-empty-list-placeholder for empty accounts/wallets/items, plus data-empty-state One distinction worth noting: a present-but-blank address (`""`) is an empty state, while a missing one (`null`) stays the ordinary disconnected badge unless the caller passes placeholder copy. The branch's own tests require both readings. All four wallet-badge suites now pass together. lint 0 errors / tsc 0 errors / 2052 tests passing / build OK
The branch's lockfile is not valid JSON -- it fails to parse at offset 101100 in the branch itself, before any merge -- which is why CI died at "Install dependencies" with npm error code EUSAGE rather than at a lint or test step. The branch does not modify package.json at all, so its 5002-line lockfile change had nothing to express; main's lockfile is the correct one for these dependencies. Verified with a clean npm ci against the merged package.json. lint 0 errors / tsc 0 errors / 2052 tests passing / build OK
…ole-errors-and-transaction-tracking-in-network-sync-checker # Conflicts: # __tests__/freighter_connector.component.test.tsx # __tests__/freighter_multisig_hook.test.ts # __tests__/signature_timeout_alert.test.tsx # __tests__/signature_timeout_alert_timeout.test.ts # app/components/SignatureTimeoutAlert.tsx # vitest.setup.ts
…pty-placeholder feat(wallet): render descriptive placeholders for empty data states in wallet_badge
…lready carries This branch and its three siblings (Goldii-locks#359/Goldii-locks#360/Goldii-locks#361) share a base of commits that rework the same four test files and SignatureTimeoutAlert, so most of the conflict here is the same work expressed twice: - signature_timeout_alert_timeout.test.ts: `onRejected` vs main's `settled` for the same catch-before-advance handle. - freighter_multisig_hook.test.ts: an equivalent signed-envelope builder to main's `buildSignedEnvelopeXdr`. - signature_timeout_alert.test.tsx: the same act() calls, reformatted. - freighter_connector.component.test.tsx: a different mocking strategy for the same cases. None of those four adds a test case -- the it() counts are identical to this branch's own merge base -- so main's versions were kept and this branch's rewrites dropped. SignatureTimeoutAlert took the branch's explanatory comment, which describes what main already does. vitest.setup.ts combines both: the branch's guard is the better one (it also catches the experimental Node localStorage global that reads as undefined and shadows jsdom's), while main's defined the property on both globalThis and window. The merged version does both. The branch's actual deliverable is untouched: NetworkSyncChecker.tsx and its 300-line component suite. lint 0 errors / tsc 0 errors / 2061 tests passing / build OK
…ct-testing-library-assertions-for-network-sync-checker [162] Write React Testing Library assertions for network_sync_checker
…eractive-states-for-notification-bell # Conflicts: # __tests__/freighter_connector.component.test.tsx # __tests__/freighter_multisig_hook.test.ts # __tests__/signature_timeout_alert.test.tsx # __tests__/signature_timeout_alert_timeout.test.ts # app/components/SignatureTimeoutAlert.tsx # app/components/notification_bell.tsx # vitest.setup.ts
Only vitest.setup.ts conflicted, and main already carries the combined version resolved on Goldii-locks#358 -- which includes this branch's own guard for the experimental Node localStorage global. Took main's. The branch's deliverable lands unchanged: the network_sync_checker logging rework and its 197-line suite. lint 0 errors / tsc 0 errors / 2072 tests passing / build OK
…y-list-views-for-notification-bell # Conflicts: # __tests__/freighter_connector.component.test.tsx # __tests__/freighter_multisig_hook.test.ts # __tests__/signature_timeout_alert.test.tsx # __tests__/signature_timeout_alert_timeout.test.ts # app/components/notification_bell.tsx # vitest.setup.ts
…nsole-errors-and-transaction-tracking-in-network-sync-checker [161] Format console errors and transaction tracking in network_sync_checker
…nteractive-states-for-notification-bell [321] Add premium interactive states to notification_bell
…pty-list-views-for-notification-bell [323] Design empty list display views for notification_bell
…e modal The branch predates Goldii-locks#375's rewrite of DisputeRaiseModal, and its own edit to that file is broken independently of the merge: it deletes the counterparty <dd>'s closing tags and splices a stray label/textarea fragment in their place, so the branch does not parse. The merge inherited that. The lib half is sound and is the real contribution, so it was kept and the component rebuilt around it: the panel becomes a plain flex column, DISPUTE_MODAL_CLASSES.overlayWrapper takes the padding and the height cap, and a scrollableContent region wraps everything between the header and the actions -- so on a short viewport the middle scrolls while the title and buttons stay pinned. Two assertions in the responsive suite described the old arrangement and now follow it: the p-4/sm:p-6/lg:p-8 checks moved from the panel to the wrapper, and the panel's overflow-y-auto check became a query for the scrollable region inside it. The branch's own "keeps action buttons clickable" case also assumed the confirm button is live with an empty reason, which Goldii-locks#375 changed -- it now fills the field first, which is what a user reaching those buttons would have done anyway. lint 0 errors / tsc 0 errors / 2098 tests passing / build OK
…spute-modal-mobile-overlay-wrappers Goldii-locks#336 Handle mobile viewports navigation styling in dispute_raise_modal
Two Navbar conflicts: this branch swaps the inline provider select and Connect button for a <WalletSelectorModal>. That is incidental to the PR -- its subject is TransactionSignerPanel (Goldii-locks#222) and none of its tests touch the Navbar -- and main's navbar-wallet-kit suite queries the select by label and the button by name, so main's Navbar was kept. TransactionSignerPanel then failed lint: it parsed the XDR in a mount effect and wrote the result to three pieces of state, which react-hooks/set-state-in-effect flags as cascading renders. Parsing is a pure function of the XDR and the wallet/network in play, so it now derives during render through useMemo. The signing lifecycle is still real state (idle -> signing -> success/error), so it stays in useState as `signingState`, with a parse failure outranking it: const state = parseErrorMessage ? "parse-error" : signingState; Rendering is unchanged -- `state`, `structure` and `parseErrorMessage` mean exactly what they did before. lint 0 errors / tsc 0 errors / 2140 tests passing / build OK
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #222
Summary
Closes issue #222 (RTL tests for
transaction_signer_component).What changed
app/components/TransactionSignerPanel.tsx— new fileA wallet-agnostic sign-transaction panel. On mount it parses the supplied
XDR, shows a human-readable transaction preview, then lets the user confirm
or cancel before the wallet extension is invoked.
Props:
xdrstringselectedWalletIdSupportedWalletIdnetworkPassphrasestring?signTransaction(xdr) => Promise<string>onSigned(signedXdr) => voidonRejected() => void?onError(error) => void?labelstring?States:
parse-error XDR unparseable on mount → error message + Dismiss idle Structure preview + Sign + Cancel signing Buttons disabled, spinner, wallet extension open success Green confirmation, onSigned fired error Red error message, Retry + Cancel, onError fired
Signing is 100% delegated to
useWalletMultiSigAssembly— no new XDRparsing or signing logic. Works for all four wallets (freighter, albedo,
xbull, hana) through the unified hook.
No regressions
Test Files 18 passed (18) Tests 266 passed (266)